/*-------------------------------------------------------------------------
 *
 * heapdesc.c
 *	  访问/heap/heapam.c 的 rmgr 描述例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/access/rmgrdesc/heapdesc.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/heapam_xlog.h"

static void fc_out_infobits(StringInfo fc_buf, uint8 fc_infobits)
{
	if (fc_infobits & XLHL_XMAX_IS_MULTI)
		appendStringInfoString(fc_buf, "IS_MULTI ");
	if (fc_infobits & XLHL_XMAX_LOCK_ONLY)
		appendStringInfoString(fc_buf, "LOCK_ONLY ");
	if (fc_infobits & XLHL_XMAX_EXCL_LOCK)
		appendStringInfoString(fc_buf, "EXCL_LOCK ");
	if (fc_infobits & XLHL_XMAX_KEYSHR_LOCK)
		appendStringInfoString(fc_buf, "KEYSHR_LOCK ");
	if (fc_infobits & XLHL_KEYS_UPDATED)
		appendStringInfoString(fc_buf, "KEYS_UPDATED ");
}

void heap_desc(StringInfo fc_buf, XLogReaderState *fc_record)
{
	char	   *fc_rec = XLogRecGetData(fc_record);
	uint8		fc_info = XLogRecGetInfo(fc_record) & ~XLR_INFO_MASK;

	fc_info &= XLOG_HEAP_OPMASK;
	if (fc_info == XLOG_HEAP_INSERT)
	{
		xl_heap_insert *fc_xlrec = (xl_heap_insert *) fc_rec;

		appendStringInfo(fc_buf, "off %u flags 0x%02X", fc_xlrec->offnum,
						 fc_xlrec->flags);
	}
	else if (fc_info == XLOG_HEAP_DELETE)
	{
		xl_heap_delete *fc_xlrec = (xl_heap_delete *) fc_rec;

		appendStringInfo(fc_buf, "off %u flags 0x%02X ",
						 fc_xlrec->offnum,
						 fc_xlrec->flags);
		fc_out_infobits(fc_buf, fc_xlrec->infobits_set);
	}
	else if (fc_info == XLOG_HEAP_UPDATE)
	{
		xl_heap_update *fc_xlrec = (xl_heap_update *) fc_rec;

		appendStringInfo(fc_buf, "off %u xmax %u flags 0x%02X ",
						 fc_xlrec->old_offnum,
						 fc_xlrec->old_xmax,
						 fc_xlrec->flags);
		fc_out_infobits(fc_buf, fc_xlrec->old_infobits_set);
		appendStringInfo(fc_buf, "; new off %u xmax %u",
						 fc_xlrec->new_offnum,
						 fc_xlrec->new_xmax);
	}
	else if (fc_info == XLOG_HEAP_HOT_UPDATE)
	{
		xl_heap_update *fc_xlrec = (xl_heap_update *) fc_rec;

		appendStringInfo(fc_buf, "off %u xmax %u flags 0x%02X ",
						 fc_xlrec->old_offnum,
						 fc_xlrec->old_xmax,
						 fc_xlrec->flags);
		fc_out_infobits(fc_buf, fc_xlrec->old_infobits_set);
		appendStringInfo(fc_buf, "; new off %u xmax %u",
						 fc_xlrec->new_offnum,
						 fc_xlrec->new_xmax);
	}
	else if (fc_info == XLOG_HEAP_TRUNCATE)
	{
		xl_heap_truncate *fc_xlrec = (xl_heap_truncate *) fc_rec;
		int			fc_i;

		if (fc_xlrec->flags & XLH_TRUNCATE_CASCADE)
			appendStringInfoString(fc_buf, "cascade ");
		if (fc_xlrec->flags & XLH_TRUNCATE_RESTART_SEQS)
			appendStringInfoString(fc_buf, "restart_seqs ");
		appendStringInfo(fc_buf, "nrelids %u relids", fc_xlrec->nrelids);
		for (fc_i = 0; fc_i < fc_xlrec->nrelids; fc_i++)
			appendStringInfo(fc_buf, " %u", fc_xlrec->relids[fc_i]);
	}
	else if (fc_info == XLOG_HEAP_CONFIRM)
	{
		xl_heap_confirm *fc_xlrec = (xl_heap_confirm *) fc_rec;

		appendStringInfo(fc_buf, "off %u", fc_xlrec->offnum);
	}
	else if (fc_info == XLOG_HEAP_LOCK)
	{
		xl_heap_lock *fc_xlrec = (xl_heap_lock *) fc_rec;

		appendStringInfo(fc_buf, "off %u: xid %u: flags 0x%02X ",
						 fc_xlrec->offnum, fc_xlrec->locking_xid, fc_xlrec->flags);
		fc_out_infobits(fc_buf, fc_xlrec->infobits_set);
	}
	else if (fc_info == XLOG_HEAP_INPLACE)
	{
		xl_heap_inplace *fc_xlrec = (xl_heap_inplace *) fc_rec;

		appendStringInfo(fc_buf, "off %u", fc_xlrec->offnum);
	}
}
void heap2_desc(StringInfo fc_buf, XLogReaderState *fc_record)
{
	char	   *fc_rec = XLogRecGetData(fc_record);
	uint8		fc_info = XLogRecGetInfo(fc_record) & ~XLR_INFO_MASK;

	fc_info &= XLOG_HEAP_OPMASK;
	if (fc_info == XLOG_HEAP2_PRUNE)
	{
		xl_heap_prune *fc_xlrec = (xl_heap_prune *) fc_rec;

		appendStringInfo(fc_buf, "latestRemovedXid %u nredirected %u ndead %u",
						 fc_xlrec->latestRemovedXid,
						 fc_xlrec->nredirected,
						 fc_xlrec->ndead);
	}
	else if (fc_info == XLOG_HEAP2_VACUUM)
	{
		xl_heap_vacuum *fc_xlrec = (xl_heap_vacuum *) fc_rec;

		appendStringInfo(fc_buf, "nunused %u", fc_xlrec->nunused);
	}
	else if (fc_info == XLOG_HEAP2_FREEZE_PAGE)
	{
		xl_heap_freeze_page *fc_xlrec = (xl_heap_freeze_page *) fc_rec;

		appendStringInfo(fc_buf, "cutoff xid %u ntuples %u",
						 fc_xlrec->cutoff_xid, fc_xlrec->ntuples);
	}
	else if (fc_info == XLOG_HEAP2_VISIBLE)
	{
		xl_heap_visible *fc_xlrec = (xl_heap_visible *) fc_rec;

		appendStringInfo(fc_buf, "cutoff xid %u flags 0x%02X",
						 fc_xlrec->cutoff_xid, fc_xlrec->flags);
	}
	else if (fc_info == XLOG_HEAP2_MULTI_INSERT)
	{
		xl_heap_multi_insert *fc_xlrec = (xl_heap_multi_insert *) fc_rec;

		appendStringInfo(fc_buf, "%d tuples flags 0x%02X", fc_xlrec->ntuples,
						 fc_xlrec->flags);
	}
	else if (fc_info == XLOG_HEAP2_LOCK_UPDATED)
	{
		xl_heap_lock_updated *fc_xlrec = (xl_heap_lock_updated *) fc_rec;

		appendStringInfo(fc_buf, "off %u: xmax %u: flags 0x%02X ",
						 fc_xlrec->offnum, fc_xlrec->xmax, fc_xlrec->flags);
		fc_out_infobits(fc_buf, fc_xlrec->infobits_set);
	}
	else if (fc_info == XLOG_HEAP2_NEW_CID)
	{
		xl_heap_new_cid *fc_xlrec = (xl_heap_new_cid *) fc_rec;

		appendStringInfo(fc_buf, "rel %u/%u/%u; tid %u/%u",
						 fc_xlrec->target_node.spcNode,
						 fc_xlrec->target_node.dbNode,
						 fc_xlrec->target_node.relNode,
						 ItemPointerGetBlockNumber(&(fc_xlrec->target_tid)),
						 ItemPointerGetOffsetNumber(&(fc_xlrec->target_tid)));
		appendStringInfo(fc_buf, "; cmin: %u, cmax: %u, combo: %u",
						 fc_xlrec->cmin, fc_xlrec->cmax, fc_xlrec->combocid);
	}
}

const char * heap_identify(uint8 fc_info)
{
	const char *fc_id = NULL;

	switch (fc_info & ~XLR_INFO_MASK)
	{
		case XLOG_HEAP_INSERT:
			fc_id = "INSERT";
			break;
		case XLOG_HEAP_INSERT | XLOG_HEAP_INIT_PAGE:
			fc_id = "INSERT+INIT";
			break;
		case XLOG_HEAP_DELETE:
			fc_id = "DELETE";
			break;
		case XLOG_HEAP_UPDATE:
			fc_id = "UPDATE";
			break;
		case XLOG_HEAP_UPDATE | XLOG_HEAP_INIT_PAGE:
			fc_id = "UPDATE+INIT";
			break;
		case XLOG_HEAP_HOT_UPDATE:
			fc_id = "HOT_UPDATE";
			break;
		case XLOG_HEAP_HOT_UPDATE | XLOG_HEAP_INIT_PAGE:
			fc_id = "HOT_UPDATE+INIT";
			break;
		case XLOG_HEAP_TRUNCATE:
			fc_id = "TRUNCATE";
			break;
		case XLOG_HEAP_CONFIRM:
			fc_id = "HEAP_CONFIRM";
			break;
		case XLOG_HEAP_LOCK:
			fc_id = "LOCK";
			break;
		case XLOG_HEAP_INPLACE:
			fc_id = "INPLACE";
			break;
	}

	return fc_id;
}

const char * heap2_identify(uint8 fc_info)
{
	const char *fc_id = NULL;

	switch (fc_info & ~XLR_INFO_MASK)
	{
		case XLOG_HEAP2_PRUNE:
			fc_id = "PRUNE";
			break;
		case XLOG_HEAP2_VACUUM:
			fc_id = "VACUUM";
			break;
		case XLOG_HEAP2_FREEZE_PAGE:
			fc_id = "FREEZE_PAGE";
			break;
		case XLOG_HEAP2_VISIBLE:
			fc_id = "VISIBLE";
			break;
		case XLOG_HEAP2_MULTI_INSERT:
			fc_id = "MULTI_INSERT";
			break;
		case XLOG_HEAP2_MULTI_INSERT | XLOG_HEAP_INIT_PAGE:
			fc_id = "MULTI_INSERT+INIT";
			break;
		case XLOG_HEAP2_LOCK_UPDATED:
			fc_id = "LOCK_UPDATED";
			break;
		case XLOG_HEAP2_NEW_CID:
			fc_id = "NEW_CID";
			break;
		case XLOG_HEAP2_REWRITE:
			fc_id = "REWRITE";
			break;
	}

	return fc_id;
}
